//////============== 异步回调 ========================
// 回调是JS语言中最基础的异步模式.
// 以下代码有两个执行块: A.现在执行的部分; B.将来执行的部分。
// A.现在执行 
//     let answer=now(); setTimeout(later,2000);
// B.将来执行
//     answer = answer*2; console.log('...');
// 任何时候，只要将代码包装成一个函数，并指定它在响应某个事件(定时器、鼠标点击、AJAX响应等)时执行
// 就相当于在代码中创建了一个 **将来** 执行的块，也由此在这个程序中引入了异步机制。
function ajax(url:string,fn:Function):void {
    console.log("visit...."+url);
    setTimeout(cbFun,300);    
}

let answer = now();
function now() {
    return 21;
}
function later() {
    answer = answer*2;
    console.log("Meaning of life:",answer);
}

setTimeout(later,2000);


/// =============== 通过门(gate)的方式可以用来解决多异步之间的协调 ======================
// 通过门可以解决多个条件满足后，才能执行下个步骤的问题。
// 在以下这个例子中，无论 foo() 和 bar() 哪一个先被触发，总会使 baz() 过早运行（a 或者 b 仍处 于未定义状态）
let a1 : number;
let a2 : number;
function processA1(x:number) {
    a1 = x*2;
    baz();
}
function processA2(y:number) {
    a2 = y*2;
    baz();
}
function baz() {
    console.log(a1+a2);
}
ajax("http://some.url.1",processA1);
ajax("http://some.url.2",processA2);

// 通过设置gate,可以解决并发运行数据一致性的问题。
function processB1(x:number) {
    a1 = x*2;
    // 通过两个条件判断，这种技术称为门(gate)
    if(a1&&a2) {
        baz();
    }
}
function processB2(y:number) {
    a2 = y*2;
    if(a1&&a2) {
        baz();
    }
}
ajax("http://some.url.1",processB1);
ajax("http://some.url.2",processB2);



/// =================== 并发交互条件的竞争态,门闩（latch）===================
// 特性可以描述为，谁先到达，谁先获胜。 需要“竞争”到终点，且只有唯一的胜利者。
let latchVariable : boolean = false
function processC1(x:number) {
    if(!latchVariable) {
        latchVariable = true;
        baz();
    }
}
function processC2(y:number) {
    if(!latchVariable) {
        latchVariable = true;
        baz();
    }
}
ajax("http://some.url.1",processC1);
ajax("http://some.url.2",processC2);


/// =============== 并发协作(cooperative concurrency).========================= 
// 不再是通过共享作用域中的值进行交互，而是可以取到一个长期运行的进程，将其分隔成多个步骤或任务。
// 使得其它并发进程有机会将自己的去处事件循环队列中交替运行
// Sample1 : 当处理一个大任务时，可以将大任务分解成多个任务，以便不会让此一个任务霸占一个长时间的周期，让其它等待事件有机会运行。
let resultDatas :number[] = [];

function doingBigData(bigData:number[]) {
    // 处理大数据的情况下，每次只处理1000个
    let chunk : number[] = bigData.splice(0,1000);

    
    // 添加到已处理的数据中
    resultDatas = resultDatas.concat(
        chunk.map(x=>x*2)
    );

    // 剩余数据的处理
    if(bigData.length>0) {
        // 使用 setTimeout(..0)（hack）进行异步调度，基本上它的意思就是“把这个函数插入
        // 到当前事件循环队列的结尾处
        setTimeout(function(){doingBigData(bigData);},0);
    }
}
ajax("http://some.url.2",doingBigData);


///// ================ 任务队列(Job Queue) ======================
// 在新的ES6中，新的概念建立在事件循环队列之上，叫作任务队列（job queue）
// 从这个概念衍生出来的最大影响就是 Promise 的异步特性

// 任务队列 : 它是挂在事件循环队列的每个 tick 之后的一个队列。
// 在事件循环的每个 tick 中，可能出现的异步动作不会导致一个完整的新事件添加到事件循环队列中，
// 而会在当前 tick 的任务队列末尾添加一个项目（一个任务）

// 事件循环队列(Event Queue) : 相当于游乐园游戏，玩过一次之后，需要重新到队尾排除才能再玩一次。
// 任务队列(Job Queue) : 玩过了游戏之后，插队继续玩
//   ** 一个任务队列可能引起更多的任务被添加到同一个队列末尾，理论上说，任务队列可能无限循环 **
//   ** 产生上面的情况会导致进程饿死，无法移到下一个事件循环的tick, 相当于while(true){...} **
// **** Promise特性是基于任务的 *****



